package oop.ex3.crosswords;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;

/**
 * Basic implementation of CrosswordGlossary interface. Based on TreeMap<br>
 * extras and editing are documented
 * 
 * @author OOP
 * @author tsachiho
 * @author kobi_atiya
 */
public class MyCrosswordGlossary implements CrosswordGlossary {

    protected Map<String, String> data;           // Holds glossary data, maps each term to its definition.
    protected int                 quality;        // whole glossary quality

    final char                    SEPARATOR = ':'; // Line separator symbol

    /**
     * Copy Constructor
     * 
     * @param other - other MyCrosswordGlossary
     */
    public MyCrosswordGlossary(MyCrosswordGlossary other) {
        this();
        data.putAll(other.getData());
        quality = other.getQuality();
    }

    /**
     * Constructor, creates empty Glossary<br>
     * in order to get words from arguments, need to run load(FilePath);
     */
    public MyCrosswordGlossary() {
        data = new TreeMap<String, String>(new MyCrosswordGlossaryComparator<String>());
        quality = 0;
    }

    private Map<String, String> getData() {
        return data;
    }

    /*
     * @see oop.ex3.crosswords.CrosswordGlossary#getTermDefinition(java.lang.String)
     */
    public String getTermDefinition(String term) {
        return this.data.get(term);
    }

    /**
     * return glossary quality
     * 
     * @return glossary quality
     */
    public int getQuality() {
        return quality;
    }

    /**
     * add term into glossary, if already contained, update the record.
     * 
     * @param term - term
     * @param def - definition
     */
    public void put(String term, String def) {
        if (!data.containsKey(term)) quality += MyCrosswordGlossaryComparator.eval(term);
        data.put(term.toLowerCase(), def);

    }

    /**
     * remove term from glossary
     * 
     * @param term - the term to remove
     * @return - the previous definition associated with term
     */
    public String remove(String term) {
        quality -= MyCrosswordGlossaryComparator.eval(term);
        return data.remove(term);
    }

    /**
     * returning terms "value" according to the calculating rules (in the comparator)
     * 
     * @param term - term to evaluate
     * @return - the terms value (currently, it's length
     */
    public static int getlength(String term) {
        return MyCrosswordGlossaryComparator.eval(term);
    }

    /*
     * @see oop.ex3.crosswords.CrosswordGlossary#getTerms()
     */
    public Set<String> getTerms() {
        return this.data.keySet();
    }

    /*
     * @see oop.ex3.crosswords.CrosswordGlossary#load(java.lang.String)
     */
    public void load(String glossFileName) throws IOException {
        HashSet<String> glosCheck = new HashSet<String>();
        int counter = 1;
        String word, glos;
        Scanner sc = null;
        try {
            // Initialize a scanner to access the file
            sc = new Scanner(new FileReader(glossFileName));

            // Go over the lines of the file
            while (sc.hasNextLine()) {

                String entryLine = sc.nextLine();

                int separatorPosition = entryLine.indexOf(SEPARATOR);
                if (separatorPosition != -1) { // line doesn'r contain ":"

                    // Fetch the term of the current line
                    word = entryLine.substring(0, separatorPosition);

                    // Skip untrue words
                    if (word.length() < 2) continue;

                    // fetch definition of current line
                    glos = entryLine.substring(separatorPosition + 1);

                    // Adding stars to repetitive glosses for convenience
                    // If you implement your dictionary you don't have to do it
                    while (glosCheck.contains(glos))
                        glos += "*";

                    glosCheck.add(glos);
                } else {
                    // Handling lines that don't contain the ":" separartor.
                    // Again, you don't have to do it as you can assume valid input file.
                    // If there is no ":", definitions are represented as numbers
                    word = entryLine;
                    glos = "Dummy" + counter;
                }

                // Ignoring repetitive terms
                put(word.toLowerCase(), glos);
                counter++;
            }
        } finally {
            if (sc != null) sc.close();
        }
    }

}